package com.xiva.es.util;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.PutMappingRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.index.query.functionscore.ScriptScoreFunctionBuilder;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * git push -u origin v6.8.3
 *
 * @Description ES相关操作示例
 * @Author XIVA
 * @Date 2019/10/23
 */
public class EsOptUtil
{

    private static String indexName = "xiva-test";

    private static RestHighLevelClient restHighLevelClient;

    static
    {
//        HttpHost esNode1 = new HttpHost("10.200.152.77", 19200);
//        HttpHost esNode1 = new HttpHost("192.168.88.129", 9200);

        HttpHost esNode1 = new HttpHost("10.200.152.77", 29200);
        RestClientBuilder clientBuilder = RestClient.builder(esNode1);

        restHighLevelClient = new RestHighLevelClient(clientBuilder);
    }

    /**
     * 创建索引
     *
     * 相关字段类型清单如下：
     * 一级分类	二级分类	具体类型
     * 核心类型	字符串类型	text,keyword
     * 整数类型	integer,long,short,byte
     * 浮点类型	double,float,half_float,scaled_float
     * 逻辑类型	boolean
     * 日期类型	date
     * 范围类型	range
     * 二进制类型	binary
     * 复合类型	数组类型	array
     * 对象类型	object
     * 嵌套类型	nested
     * 地理类型	地理坐标类型	geo_point
     * 地理地图	geo_shape
     * 特殊类型	IP类型	ip
     * 范围类型	completion
     * 令牌计数类型	token_count
     * 附件类型	attachment
     * 抽取类型	percolator
     *
     * @throws Exception
     */
    public static void createIndex() throws Exception
    {
        GetIndexRequest request = new GetIndexRequest("indexName");

        boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);

        // 不存在，则创建index
        if (!exists)
        {
            CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);

            createIndexRequest.settings(Settings.builder().put("index.number_of_shards", 5).put("index.number_of_replicas", 0));

            XContentBuilder builder = XContentFactory.jsonBuilder();
            builder.startObject();
            {
                builder.startObject("properties");
                {
                    builder.startObject("ajmc");
                    builder.field("type", "keyword");
                    builder.endObject();

                    builder.startObject("ajlx");
                    builder.field("type", "integer");
                    builder.endObject();

                    builder.startObject("ajlb");
                    builder.field("type", "text");
                        builder.startObject("fields");
                            builder.startObject("ajlbcountfiled");
                            builder.field("type", "keyword");
                            builder.field("ignore_above", 32);
                            builder.endObject();
                        builder.endObject();
                    builder.endObject();

                    builder.startObject("fasj");
                    builder.field("type", "date");
                    builder.field("format", "yyyy-MM-dd HH:mm:ss||epoch_millis");
                    builder.endObject();

                }
                builder.endObject();
            }
            builder.endObject();
            createIndexRequest.mapping("case-type", builder);

            CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequest, RequestOptions.DEFAULT);
            boolean acknowledged = createIndexResponse.isAcknowledged();
            boolean shardsAcknowledged = createIndexResponse.isShardsAcknowledged();

            if (!acknowledged || !shardsAcknowledged)
            {
                throw new Exception("写入数据时动态建" + indexName + "失败!");
            }
        }
        else
        {
            System.out.println("index " + indexName + " exsit.");
        }

        restHighLevelClient.close();
    }


    public static void updateIndexFields() throws Exception
    {
        GetIndexRequest request = new GetIndexRequest(indexName);

        boolean exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);

        // 不存在，则创建index
        if (exists)
        {
            PutMappingRequest putMappingRequest = new PutMappingRequest(indexName);

//            createIndexRequest.settings(Settings.builder().put("index.number_of_shards", 5).put("index.number_of_replicas", 0));

            XContentBuilder builder = XContentFactory.jsonBuilder();
            builder.startObject();
            {
                builder.startObject("properties");
                {
                    builder.startObject("ajnr");
                    builder.field("type", "text");
                    builder.field("analyzer", "ik_max_word");
                    builder.field("search_analyzer", "ik_smart");
                    builder.endObject();
                }
                builder.endObject();
            }
            builder.endObject();

            putMappingRequest.source(builder);

            AcknowledgedResponse acknowledgedResponse = restHighLevelClient.indices().putMapping(putMappingRequest, RequestOptions.DEFAULT);
            boolean acknowledged = acknowledgedResponse.isAcknowledged();

            if (!acknowledged)
            {
                throw new Exception("写入数据时动态建" + indexName + "失败!");
            }
        }
        else
        {
            System.out.println("index " + indexName + "not exsit.");
        }

        restHighLevelClient.close();
    }

    /**
     * 插入数据
     *
     * @throws IOException
     */
    public static void insertDoc() throws IOException
    {
        CaseInfo caseInfo = new CaseInfo();
        caseInfo.setAjmc("李四xxx商场盗窃案");
//        caseInfo.setFasj(DateUtils.parseDate("2019-10-23 10:56:55"));
        caseInfo.setFasj(DateUtil.parse("2019-10-27 10:56:55"));
        caseInfo.setAjlb("xzaj");
        caseInfo.setAjlx(1);
        caseInfo.setId("4");
        caseInfo.setAjnr("Topic 相当于消息的分配标签，是一个逻辑概念。主题好比是数据库的表，或者文件系统中的文件夹。");

        String caseInfoJson = JSON.toJSONString(caseInfo);

        // 不指定ID时，随机生成，如：GxbbEW4BiMObJsMQWO-H
        IndexRequest indexRequest = new IndexRequest(indexName, "case-type", caseInfo.getId()).source(caseInfoJson, XContentType.JSON);

        IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);

        System.out.println(indexResponse.toString());
    }

    /**
     * 更新数据
     *
     * @throws IOException
     */
    public static void updateDoc() throws IOException
    {
        // 可通过查询获取ID
        UpdateRequest updateRequest = new UpdateRequest(indexName, "case-type", "JRa6AW4BiMObJsMQXR8c");

        IndexRequest indexRequest = new IndexRequest();
        Map<String, String> source = new HashMap<String, String>();
        source.put("ajmc", "修改后的案件名称-李四盗窃案");
        indexRequest.source(source);

        updateRequest.doc(indexRequest);

        UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);

        System.out.println(updateResponse);

    }


    /**
     * 删除数据
     *
     * @throws IOException
     */
    public static void deleteData() throws IOException
    {
        // 可通过查询获取ID
        DeleteRequest deleteRequest = new DeleteRequest(indexName, "case-type", "JRa6AW4BiMObJsMQXR8c");

        DeleteResponse deteleResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);

        System.out.println(deteleResponse);
    }

    /**
     * 查找数据
     *
     * @throws IOException
     */
    public static void queryData() throws IOException
    {
        SearchRequest request = new SearchRequest(indexName);

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.termQuery("ajlx", "2"));

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(boolQueryBuilder);

        request.searchType(SearchType.DEFAULT).source(searchSourceBuilder);

        SearchResponse searchResponse = restHighLevelClient.search(request, RequestOptions.DEFAULT);

        System.out.println(searchResponse.getHits().totalHits);
    }


    public static void queryDataByIK() throws IOException
    {
        SearchRequest request = new SearchRequest(indexName);

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(QueryBuilders.termQuery("ajnr", "kafka"));

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(boolQueryBuilder);

        request.searchType(SearchType.DEFAULT).source(searchSourceBuilder);

        SearchResponse searchResponse = restHighLevelClient.search(request, RequestOptions.DEFAULT);

        System.out.println(searchResponse.getHits().totalHits);
    }

    /**
     * 汇聚数据
     */
    public static void aggregationData() throws IOException
    {
        SearchRequest request = new SearchRequest(indexName);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        // es无法对text字段直接做聚合，需要使用field下面的keyword做聚合;默认text和keyword类型，自动创建一个keyword字段。
        // 还有一种解决办法是设置"fielddata": true，但是消耗内存
//        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("by_ajlb").field("ajlb.keyword");
        TermsAggregationBuilder aggregationBuilder = AggregationBuilders.terms("by_ajlb").field("ajlb.ajlbcountfiled");
        searchSourceBuilder.aggregation(aggregationBuilder);

        request.searchType(SearchType.DEFAULT).source(searchSourceBuilder);

        SearchResponse searchResponse = restHighLevelClient.search(request, RequestOptions.DEFAULT);

        Terms ajlxAgg = (Terms)searchResponse.getAggregations().get("by_ajlb");

        for (Terms.Bucket buckets : ajlxAgg.getBuckets())
        {
            System.out.println("keys:" + buckets.getKeyAsString() + "; values:" + buckets.getDocCount());
        }

//        System.out.println(searchResponse.getHits().totalHits);
    }

    public static void searchImageByScore() throws IOException
    {
        SearchRequest request = new SearchRequest("motorvehicle");


        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        Map<String, Object> params = new HashMap<>();
        params.put("source_field_name", "Feature");
        params.put("compare_val", "KC5QNwAAAAAAAAAAAAAAAMwfwzoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5oujoP5NU5wJhfPQAAAAAAAAAAAAAAALNOmzMAAAAAAAAAAAAAAAAAAAAAAAAAAEbPvzUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL7ABzEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmX46PGxgcDYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADuUvE4AAAAAAAAAAAAAAAAAAAAAAAAAADfo04+AAAAAAAAAAAAAAAAAAAAAJFpkDQAAAAAw8XCO2xsHDgAAAAAAAAAAAAAAABNbnc+AAAAAAAAAACrZ/U0Tmx9PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABchQ81AAAAAJw4DTEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAi/5I8AAAAAKHr9joAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC+XP08AAAAAAAAAAC0fvY7AAAAAAAAAAACt5Y5AAAAAAAAAAAAAAAAAAAAAJ6ueTYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADXL0YzAAAAAAAAAADV2wE2AAAAAIHd2DoAAAAA3f3TNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3vpOMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGFJQ3AAAAAPlpITwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACKhsg9AAAAAAAAAADAFL46AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGTYijUAAAAAAAAAAAAAAACJDCUxaf2cNwAAAABCMPk6AAAAAAAAAAAAAAAAAAAAAMzNqTsAAAAA9AbmPQAAAADLddw9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAngPvOwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiUVVPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOfJNzkAAAAAaazvOwAAAAAAAAAAG/hbMwAAAAAmy7w9AAAAAAAAAAAAAAAAeHalPQAAAAAAAAAAAAAAAAAAAAAAAAAA0zAENzuiuT4AAAAAAAAAABRQ9juGKk8uAAAAAAAAAAAAAAAAAAAAAAAAAACEikY9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEumAvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHPXUD4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFGHCD8AAAAA1NGeOQAAAAAiLz89AAAAAAAAAAAAAAAAz5YEPgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADmhajwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJypRMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE0qPKHqjj4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ0OczoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMpOdTkAAAAAAAAAACDnDzoAAAAAAAAAAAAAAAAAAAAARDmRNQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGkGjD0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArxfYtAAAAAPejDTUAAAAAAAAAAAAAAAD+v2g9AAAAAIfYGD4AAAAAAAAAAI6BlzsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWykdMQAAAAAAAAAABopmOXe66T0AAAAArP/rOgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMf/6PQAAAAAAAAAAAAAAAGgy3T4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAz9KDSV2yw9AAAAAAAAAAA=");
        Script script = new Script(ScriptType.INLINE,"feature_compare","grgbanking_feature_compare" , params);
        ScriptScoreFunctionBuilder scriptBuilder = ScoreFunctionBuilders.scriptFunction(script);

        FunctionScoreQueryBuilder functionScoreQueryBuilder = new FunctionScoreQueryBuilder(boolQueryBuilder, scriptBuilder);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        searchSourceBuilder.query(functionScoreQueryBuilder);

        request.searchType(SearchType.DEFAULT).source(searchSourceBuilder);

        SearchResponse searchResponse = restHighLevelClient.search(request, RequestOptions.DEFAULT);

        System.out.println(searchResponse.getHits().totalHits);
    }

    public static void main(String[] args) throws Exception
    {

        try
        {
//            createIndex();
//            updateIndexFields();
//            insertDoc();

//            updateDoc();
//            deleteData();

//            queryData();
//            queryDataByIK();
//            aggregationData();

            searchImageByScore();

        }
        catch (Exception e)
        {
            e.printStackTrace();
        }

        restHighLevelClient.close();
    }

}
